package screen;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;

import javax.vecmath.Color3f;

public class ScreenBuffer {

	public static final Dimension SCREEN = new Dimension(800, 600);

	private Pixel[][] pixelBuffer;
	private float maxLightLuminance = 1.5f;

	public ScreenBuffer() {
		pixelBuffer = new Pixel[(int) SCREEN.getWidth()][(int) SCREEN
				.getHeight()];
		for (int i = 0; i < pixelBuffer.length; i++) {
			for (int j = 0; j < pixelBuffer[i].length; j++) {
				pixelBuffer[i][j] = new Pixel();
			}
		}
	}

	public void addColorToPixel(Point2D pixel, Color3f color) {
		Color3f toneReproColor = this.toneReproduction(color.getX(), color
				.getY(), color.getZ());
		pixelBuffer[(int) pixel.getX()][(int) pixel.getY()]
				.addColor(toneReproColor);
	}

	public void draw(Graphics2D g2d) {
		for (int i = 0; i < pixelBuffer.length; i++) {
			for (int j = 0; j < pixelBuffer[i].length; j++) {
				Color3f average = pixelBuffer[i][j].averageColors();
				average.clampMin(0.0f);
				average.setX(this.getInDisplayableRange(average.getX()));
				average.setY(this.getInDisplayableRange(average.getY()));
				average.setZ(this.getInDisplayableRange(average.getZ()));
				g2d.setColor(new Color(average.getX(), average.getY(), average
						.getZ()));
				g2d.fillRect(i, j, 1, 1);
			}
		}
	}

	private float getInDisplayableRange(float v) {
		return v / maxLightLuminance;
	}

	private Color3f toneReproduction(float r, float g, float b) {
		// return new Color3f(this.ward(r), this.ward(g), this.ward(b));
		return new Color3f(this.reinhard(r), this.reinhard(g), this.reinhard(b));
	}

	public float ward(float luminance) {
		float sf = (float) ((1.0f / 100.0f) * Math.pow((1.219f + Math.pow(
				100.0f / 2.0f, 0.4f))
				/ (1.219f + Math.pow(1.0f, 0.4f)), 2.5f));
		return luminance * sf;
	}

	public float reinhard(float luminance) {
		return (float) ((luminance * (1.0f + (luminance / Math.pow(5.0f, 2.0f)))) / (1.0f + luminance));
	}

}
